package com.bjsxt.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bjsxt.config.geetest.GeetestLib;
import com.bjsxt.config.idcard.IdentityProperties;
import com.bjsxt.domain.Sms;
import com.bjsxt.domain.User;
import com.bjsxt.domain.UserAuthAuditRecord;
import com.bjsxt.domain.UserAuthInfo;
import com.bjsxt.dto.*;
import com.bjsxt.mapper.UserMapper;
import com.bjsxt.mappers.UserDtoMapper;
import com.bjsxt.model.UserVo;
import com.bjsxt.service.SmsService;
import com.bjsxt.service.UserAuthAuditRecordService;
import com.bjsxt.service.UserAuthInfoService;
import com.bjsxt.service.UserService;
import com.bjsxt.util.GeetestUtil;
import com.bjsxt.util.SpringSecurityUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.*;
import org.springframework.security.crypto.bcrypt.BCrypt;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.web.client.RestTemplate;

import java.util.*;
import java.util.stream.Collectors;

import static com.bjsxt.costant.SmsTypeConstants.*;

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    /**
     * 创建一个发送请求的工具对象
     */
    private final RestTemplate restTemplate = new RestTemplate();
    /**
     * 审核记录业务层接口
     */
    @Autowired
    private UserAuthAuditRecordService userAuthAuditRecordService;
    /**
     * 注入身份证认证的信息配置对象
     */
    @Autowired
    private IdentityProperties identityProperties;
    /**
     * Redis 客户端操作对象
     */
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    /**
     * 极验验证核心类
     */
    @Autowired
    private GeetestLib geetestLib;

    /**
     * 用户实名认证信息业务层接口
     */
    @Autowired
    private UserAuthInfoService userAuthInfoService;

    /**
     * 雪花算法 ID 生成器
     */
    @Autowired
    private Snowflake snowflake;

    /**
     * String 类型的 redis 的客户端操作对象
     */
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 短信服务业务层对象
     */
    @Autowired
    private SmsService smsService;

    /**
     * 根据手机号, 会员的 id, 用户名, 真实姓名, 状态分页查询员工数据
     *
     * @param page          分页对象<User>
     * @param mobile        手机号
     * @param userId        会员的 id, 精确查询
     * @param userName      用户名
     * @param realName      真实姓名
     * @param status        状态 0: 禁用 1: 启用
     * @param reviewsStatus 审核状态,1通过,2拒绝,0,待审核
     * @return 员工分页数据
     */
    @Override
    public Page<User> pageByMobileAndUserIdAndUserNameAndRealNameAndStatusAndReviewsStatus(Page<User> page, String mobile, Long userId, String userName, String realName, Integer status, Integer reviewsStatus) {
        // 根据响应的条件分页查询员工数据
        return page(page, new LambdaQueryWrapper<User>()
                .like(StringUtils.isNotBlank(mobile), User::getMobile, mobile)
                .eq(userId != null, User::getId, userId)
                .like(StringUtils.isNotBlank(userName), User::getUsername, userName)
                .like(StringUtils.isNotBlank(realName), User::getRealName, realName)
                .eq(status != null, User::getStatus, status)
                .eq(reviewsStatus != null, User::getReviewsStatus, reviewsStatus)
        );
    }

    /**
     * 根据用户 id 获取用户视图层对象
     * TODO: 这个位置用户的审核状态在后台的数据库默认值是 0 也就是说添加之后默认就是在审核，需要修改默认值
     *
     * @param id 用户 id
     * @return 用户信息对象
     */
    @Override
    public UserVo getUserVoById(Long id) {
        // 根据 id 查询当前用户
        User user = super.getById(id);
        // 如果查询的用户是空的，那么抛出异常
        Assert.notNull(user, "请输入正确的用户 ID");
        // 创建返回的 userVo 对象
        UserVo userVo = new UserVo();
        // 使用工具类对值进行 copy
        BeanUtil.copyProperties(user, userVo);
        // 根据用户的审核状态进行相应的操作
        Byte reviewsStatus = userVo.getReviewsStatus();
        // 对取出的审核状态进行判断操作
        switch (reviewsStatus) {
            case 0: // 审核中
                userVo.setSeniorAuthStatus((byte) 0);
                userVo.setSeniorAuthDesc("等待审核中");
                break;
            case 1: // 审核通过
                userVo.setSeniorAuthStatus((byte) 1);
                userVo.setSeniorAuthDesc("用户审核已通过");
                break;
            case 2: // 审核失败
                userVo.setSeniorAuthStatus((byte) 2);
                // 根据用户 id 查询审核记录
                List<UserAuthAuditRecord> records = userAuthAuditRecordService.getUserAuthAuditRecordList(id);
                // 查看该集合数据是否是空，如果不是空继续操作，如果是空，那么就给出错误的详细信息
                if (CollectionUtils.isEmpty(records)) // 给出错误的详细信息
                    userVo.setSeniorAuthDesc("未知错误信息");
                else
                    // 获取最新的记录，并将最新记录的错误信息返回回去
                    userVo.setSeniorAuthDesc(records.get(0).getRemark());
                break;
            default: // 如果上诉状态都没有，默认没有进行填写数据
                // 将用户的状态改为 3 未填写
                userVo.setSeniorAuthStatus((byte) 3);
                userVo.setSeniorAuthDesc("用户没有进行过身份认证");
                break;
        }
        // 返回用户数据对象
        return userVo;
    }

    /**
     * 通过用户的 ID 查询该用户的邀请的人员
     *
     * @param page   分页对象<User>
     * @param userId 用户的 id
     * @return 员工分页数据
     */
    @Override
    public Page<User> pageDirectInvitesByUserId(Page<User> page, Long userId) {
        // 根据相应的条件分页查询员工数据
        return page(page, new LambdaQueryWrapper<User>()
                .eq(User::getDirectInviteid, userId)
        );
    }

    /**
     * 审核
     *
     * @param id            会员的 id
     * @param reviewsStatus 审核状态,1通过,2拒绝,0,待审核
     * @param authCode      一组图片的唯一标识
     * @param remark        审核拒绝的原因(非必填)
     * @return 统一响应对象
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean audit(Long id, Byte reviewsStatus, Long authCode, String remark) {
        // 根据 id 查询会员
        User user = getById(id);
        // 如果 user 不是空
        if (user != null) {
            // 修改审核状态
            user.setReviewsStatus(reviewsStatus);
            // 修改用户
            updateById(user);
        }
        // 创建审核记录
        UserAuthAuditRecord userAuthAuditRecord = new UserAuthAuditRecord();
        // 设置基础的值
        userAuthAuditRecord.setUserId(id);
        userAuthAuditRecord.setStatus(reviewsStatus);
        userAuthAuditRecord.setAuthCode(authCode);
        userAuthAuditRecord.setAuditUserId(SpringSecurityUtils.getCurrentUserId());
        // TODO: 这里需要远程调用服务进行用户名称的查询
        userAuthAuditRecord.setAuditUserName("暂无待补充");
        userAuthAuditRecord.setRemark(remark);
        // 进行数据的保存
        return userAuthAuditRecordService.save(userAuthAuditRecord);
    }

    /**
     * 用户实名认证
     *
     * @param userId   用户 id
     * @param identify 用户实名认证数据对象
     * @return true 认证成功 false 认证失败
     */
    @Override
    public boolean identifyValidate(Long userId, IdentifyDto identify) {
        // 获取当前登录用户的数据
        User currentUser = getById(userId);
        // 查看当前的对象是否是空，如果是空抛出异常
        Assert.notNull(currentUser, "认证的用户不存在");
        // 如果当前的用户的状态不是非认证用户，抛出异常
        if (currentUser.getAuthStatus() != 0)
            throw new IllegalArgumentException("该用户已经实名认证过，不需要重复认证");
        // 验证极验的验证码
        GeetestUtil.checkFormData(identify, geetestLib, redisTemplate);
        // 调用实名认证的方法进行实名认证,并返回认证结果
        boolean flag = checkIdentity(identify.getIdCard(), identify.getRealName());
        if (flag) {
            // 认证成功，修改用户数据并保存到数据库中
            // 修改认证时间
            currentUser.setAuthtime(new Date());
            // 修改认证类型
            currentUser.setAuthStatus((byte) 1);
            // 修改真实姓名
            currentUser.setRealName(identify.getRealName());
            // 修改身份证号
            currentUser.setIdCard(identify.getIdCard());
            // 修改身份证类型
            currentUser.setIdCardType(identify.getIdCardType());
            // 更新用户信息
            return updateById(currentUser);
        }
        // 返回认证失败
        return false;
    }

    /**
     * 根据用户 id 对用户进行高级认证的操作
     * 高级认证->高级认证审核
     *
     * @param userId 用户 id
     * @param imgs   用户上传的身份证图片列表
     * @return true 保存成功 false 保存失败
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean authUser(Long userId, List<String> imgs) {
        // 判断用户的上传的图片是否是空
        Assert.notEmpty(imgs, "用户上传的身份信息图片不能为空");
        // 根据 id 查询当前用户
        User user = getById(userId);
        // 如果查询的用户是空的，那么抛出异常
        Assert.notNull(user, "用户不存在");
        // 创建 authCode 一组身份信息一个这个值
        long authCode = snowflake.nextId(); // 使用雪花算法
        // 创建一个集合，构建完数据后进行批量的数据添加
        List<UserAuthInfo> userAuthInfos = new ArrayList<>();
        // 循环遍历图片，对图片中的数据进行数据的添加
        for (int i = 0; i < imgs.size(); i++) { // 图片是有序排列的，设置身份证类型的时候
            // 创建实名认证信息，三张，使用 authCode 来区分一组，一个用户实名信息有三条这个数据
            UserAuthInfo userAuthInfo = new UserAuthInfo();
            // 设置用户 id
            userAuthInfo.setUserId(userId);
            // 设置用户上传图片
            userAuthInfo.setImageUrl(imgs.get(i));
            // 设置身份证图片类型序号
            userAuthInfo.setSerialno(i + 1); // 1-身份证正面照；2-身份证反面照；3-手持身份证照片
            // 设置一组图片的授权 authCode
            userAuthInfo.setAuthCode(authCode);
            // 进行集合数据的添加
            userAuthInfos.add(userAuthInfo);
        }
        // 调用方法进行数据批量添加
        userAuthInfoService.saveBatch(userAuthInfos);
        // 更改用户的审核状态为等待审核中
        user.setReviewsStatus((byte) 0);
        // 对用户进行更新，并对更新成功与否进行返回
        return updateById(user);
    }

    /**
     * 修改用户的手机号码
     *
     * @param userId      需要进行修改手机号的用户 ID
     * @param updatePhone 修改用户手机号的参数实体对象
     * @return true 修改成功 false 修改失败
     */
    @Override
    public boolean updatePhone(Long userId, UpdatePhoneDto updatePhone) {
        // 获取用户对象
        User user = getById(userId);
        // 获取用户的旧手机号码
        String oldMobile = user.getMobile();
        // 如果新旧手机号一致，那么就进行报错
        if (oldMobile.equals(updatePhone.getNewMobilePhone()))
            throw new IllegalArgumentException("使用的新手机和旧手机号一致");
        // 获取旧手机的验证码
        String oldMobileCode = stringRedisTemplate.opsForValue().get("SMS:" + VERIFY_OLD_PHONE + ":" + oldMobile);
        // 校验旧手机的验证码
        if (!updatePhone.getOldValidateCode().equals(oldMobileCode))
            throw new IllegalArgumentException("旧手机的验证码错误");
        // 获取旧手机的验证码
        String newMobileCode = stringRedisTemplate.opsForValue().get("SMS:" + CHANGE_PHONE_VERIFY + ":" + updatePhone.getNewMobilePhone());
        // 校验旧手机的验证码
        if (!updatePhone.getValidateCode().equals(newMobileCode))
            throw new IllegalArgumentException("新手机的验证码错误");
        // 对用户的手机号进行修改
        user.setMobile(updatePhone.getNewMobilePhone());
        // 对用户进行修改并返回
        return updateById(user);
    }

    /**
     * 校验手机号的可用状态，可用则进行发送验证码
     *
     * @param countryCode  电话的国家区号
     * @param mobile       需要验证的手机号
     * @param templateCode 短信模板ID
     * @return true 校验可用 false 校验不可用
     */
    @Override
    public boolean checkPhone(String countryCode, String mobile, String templateCode) {
        // 根据国家号和手机号查询用户
        int count = count(new LambdaQueryWrapper<User>().eq(User::getCountryCode, countryCode).eq(User::getMobile, mobile));
        // 如果查询到代表有人用这个手机号进行报错
        if (count > 0)
            throw new IllegalArgumentException("手机号已经被占用，不可重复使用");
        // 创建 SMS 对象用于发送短信
        Sms sms = new Sms();
        // 设置国际区号
        sms.setCountryCode(countryCode);
        // 设置发送验证码手机号
        sms.setMobile(mobile);
        // 设置短信模板 ID
        sms.setTemplateCode(templateCode);
        // 调用业务层对象进行数据的发送，并返回发送结果
        return smsService.sendSms(sms);
    }

    /**
     * 根据用户 id 修改用户的登录密码
     *
     * @param userId         用户 id
     * @param updatePassword 用户修改密码的参数实体类
     * @return true 修改成功 false 修改失败
     */
    @Override
    public boolean updateLoginPassword(Long userId, UpdatePasswordDto updatePassword) {
        // 根据 id 查询当前用户
        User user = getById(userId);
        // 如果查询的用户是空的，那么抛出异常
        Assert.notNull(user, "用户不存在");
        // 调用加密算法对密码进行比对是否一致
        boolean flag = BCrypt.checkpw(updatePassword.getOldPassword(), user.getPassword());
        // 如果判断结果为 false
        if (!flag)
            throw new IllegalArgumentException("您输入的旧密码不正确");
        // 获取手机的验证码信息
        String validateCode = stringRedisTemplate.opsForValue().get("SMS:" + CHANGE_LOGIN_PWD_VERIFY + ":" + user.getMobile());
        // 如果验证码不正确，那么进行提示错误
        if (!updatePassword.getValidateCode().equals(validateCode))
            throw new IllegalArgumentException("您输入的手机验证码不正确，请核对后重新输入");
        // 对用户的密码进行修改
        user.setPassword(BCrypt.hashpw(updatePassword.getNewPassword(), BCrypt.gensalt()));
        // 返回保存的结果
        return updateById(user);
    }

    /**
     * 根据用户 id 修改用户的支付密码
     *
     * @param userId         用户 id
     * @param updatePassword 用户修改密码的参数实体类
     * @return true 修改成功 false 修改失败
     */
    @Override
    public boolean updatePayPassword(Long userId, UpdatePasswordDto updatePassword) {
        // 根据 id 查询当前用户
        User user = getById(userId);
        // 如果查询的用户是空的，那么抛出异常
        Assert.notNull(user, "用户不存在");
        // 调用加密算法对密码进行比对是否一致
        boolean flag = BCrypt.checkpw(updatePassword.getOldPassword(), user.getPaypassword());
        // 如果判断结果为 false
        if (!flag)
            throw new IllegalArgumentException("您输入的旧密码不正确");
        // 获取手机的验证码信息
        String validateCode = stringRedisTemplate.opsForValue().get("SMS:" + CHANGE_PAY_PWD_VERIFY + ":" + user.getMobile());
        // 如果验证码不正确，那么进行提示错误
        if (!updatePassword.getValidateCode().equals(validateCode))
            throw new IllegalArgumentException("您输入的手机验证码不正确，请核对后重新输入");
        // 对用户的密码进行修改
        user.setPaypassword(BCrypt.hashpw(updatePassword.getNewPassword(), BCrypt.gensalt()));
        // 返回保存的结果
        return updateById(user);
    }

    /**
     * 根据用户 id 重新设置用户的交易密码
     *
     * @param userId           用户 id
     * @param resetPayPassword 重置用户密码的参数实体对象
     * @return true 重置成功 false 重置失败
     */
    @Override
    public boolean resetPayPassword(Long userId, ResetPayPasswordDto resetPayPassword) {
        // 根据 id 查询当前用户
        User user = getById(userId);
        // 如果查询的用户是空的，那么抛出异常
        Assert.notNull(user, "用户不存在");
        // 获取用户之前的支付密码，进行判断两个密码是否一致
        boolean flag = BCrypt.checkpw(resetPayPassword.getPayPassword(), user.getPaypassword());
        // 如果判断结果为 false
        if (flag)
            throw new IllegalArgumentException("新旧密码不能相同");
        // 获取手机的验证码信息
        String validateCode = stringRedisTemplate.opsForValue().get("SMS:" + FORGOT_PAY_PWD_VERIFY + ":" + user.getMobile());
        // 如果验证码不正确，那么进行提示错误
        if (!resetPayPassword.getValidateCode().equals(validateCode))
            throw new IllegalArgumentException("您输入的手机验证码不正确，请核对后重新输入");
        // 对用户的密码进行修改
        user.setPaypassword(BCrypt.hashpw(resetPayPassword.getPayPassword(), BCrypt.gensalt()));
        // 返回保存的结果
        return updateById(user);
    }

    /**
     * 根据用户 ID 查询用户的邀请列表数据
     *
     * @param userId 用户 ID
     * @return 用户的邀请列表
     */
    @Override
    public List<User> getUserInvites(Long userId) {
        // 根据直接邀请 id 查询用户列表数据
        return list(new LambdaQueryWrapper<User>().eq(User::getDirectInviteid, userId));
    }

    /**
     * 根据用户的 ID 集合查询用户的基本数据信息
     *
     * @param ids 用户的 id 集合
     * @return 用户基本信息数据集合
     */
    @Override
    public List<UserDto> listBasicByIds(List<Long> ids) {
        // 调用方法根据用户 id 查询用户集合数据
        List<User> users = listByIds(ids);
        // 如果查询的时候没有数据返回空
        if (users.isEmpty())
            return null;
        // 调用转换方法对集合数据进行转换
        return UserDtoMapper.INSTANCE.convert2Dto(users);
    }

    /**
     * 用户的注册
     *
     * @param registerDto 注册用户的参数实体对象
     * @return true 注册成功 false 注册失败
     */
    @Override
    public boolean register(RegisterDto registerDto) {
        // 判断传入的邮箱和手机号的合法性
        if (StringUtils.isNotBlank(registerDto.getEmail()) && StringUtils.isNotBlank(registerDto.getMobile()) ||
                StringUtils.isEmpty(registerDto.getEmail()) && StringUtils.isEmpty(registerDto.getMobile()))
            throw new IllegalArgumentException("手机号和邮箱参数输入错误");
        // 定义是否有这个数据的 count 值，进行擦哈希当前的手机号或者邮箱是否注册过
        int count = count(new LambdaQueryWrapper<User>()
                .eq(StringUtils.isNotBlank(registerDto.getMobile()), User::getMobile, registerDto.getMobile())
                .eq(StringUtils.isNotBlank(registerDto.getEmail()), User::getEmail, registerDto.getEmail())
        );
        if (count > 0) // 如果有这个数据，那么进行报错并返回
            throw new IllegalArgumentException("该手机号或者邮箱已经注册过，不可重复注册");
        // 验证极验的验证码
        GeetestUtil.checkFormData(registerDto, geetestLib, redisTemplate);
        // 调用方法生成用户对象
        User user = generateUser(registerDto);
        // 返回保存用户的结果
        return save(user);
    }

    /**
     * 找回用户的登录密码
     *
     * @param setPasswordDto 找回用户登录密码的参数实体类
     * @return true 找回成功 false 找回失败
     */
    @Override
    public boolean setLoginPassword(SetPasswordDto setPasswordDto) {
        // 对极验的数据进行校验
        GeetestUtil.checkFormData(setPasswordDto, geetestLib, redisTemplate);
        // 对用户的手机验证码进行校验，获取手机的验证码信息
        String validateCode = stringRedisTemplate.opsForValue().get("SMS:" + FORGOT_VERIFY + ":" + setPasswordDto.getMobile());
        // 如果验证码不正确，那么进行提示错误
        if (!setPasswordDto.getValidateCode().equals(validateCode))
            throw new IllegalArgumentException("您输入的手机验证码不正确，请核对后重新输入");
        // 根据用户的手机号码进行查询用户的操作，
        User user = getOne(new LambdaQueryWrapper<User>().eq(User::getMobile, setPasswordDto.getMobile()));
        // 如果查询不到这个用户直接报错
        Assert.notNull(user, "手机号输入错误，请核对后重新输入");
        // 判断用户的新旧密码是否相同，相同进行报错
        if (BCrypt.checkpw(setPasswordDto.getPassword(), user.getPassword()))
            throw new IllegalArgumentException("新旧密码不能一致。");
        // 对用户的数据进行修改保存操作
        user.setPassword(BCrypt.hashpw(setPasswordDto.getPassword(), BCrypt.gensalt()));
        // 调用方法进行数据的保存，并返回保存结果
        return updateById(user);
    }

    /**
     * 根据用户的 id 集合，用户的名称，用户的手机号进行查询用户的基本数据
     *
     * @param ids      用户的 id 集合
     * @param userName 用户名
     * @param mobile   手机号
     * @return key: 用户的 id，value:用户基本信息数据
     */
    @Override
    public Map<Long, UserDto> listBasicByIdsAndUserNameAndMobile(List<Long> ids, String userName, String mobile) {
        // 调用方法进行数据的查询
        List<User> users = list(new LambdaQueryWrapper<User>()
                .in(!CollectionUtils.isEmpty(ids), User::getId, ids)
                .like(StringUtils.isNotBlank(userName), User::getUsername, userName)
                .eq(StringUtils.isNotBlank(mobile), User::getMobile, mobile)
        );
        // 如果查询的时候没有数据返回空map
        if (users.isEmpty())
            return Collections.emptyMap();
        // 转换集合为 dto 对象的集合
        List<UserDto> userDtos = UserDtoMapper.INSTANCE.convert2Dto(users);
        // 返回转换的 map 对象
        return userDtos.stream().collect(Collectors.toMap(UserDto::getId, userDto -> userDto));
    }

    /**
     * 调用这个方法进行用户身份证信息的校验
     *
     * @param idCard   身份证号
     * @param realName 真实姓名
     * @return true 校验成功 false 校验失败
     */
    private boolean checkIdentity(String idCard, String realName) {
        // 创建需要请求的路径和请求信息
        String urlSend = identityProperties.getHost() + identityProperties.getPath() + "?idCard=" + idCard + "&name=" + realName;
        // 创建请求头
        HttpHeaders httpHeaders = new HttpHeaders();
        // 添加 Appcode 值
        httpHeaders.add("Authorization", "APPCODE " + identityProperties.getAppCode());
        // 发送请求进行地址的访问
        ResponseEntity<String> exchange = restTemplate.exchange(urlSend, HttpMethod.GET, new HttpEntity<>(httpHeaders), String.class);
        // 如果返回的响应是 200 那么就是响应成功
        if (exchange.getStatusCode() == HttpStatus.OK) {
            // 获取返回的响应值
            String body = exchange.getBody();
            // 将值转换成 Json 对象
            JSONObject jsonObject = JSON.parseObject(body);
            switch (jsonObject.getString("status")) {
                case "01": // 认证成功
                    return true;
                case "02": // 认证不通过
                    return false;
                case "03": // 无法认证（库无）
                    return false;
                default: // 未知错误
                    return false;
            }
        }
        // 返回校验失败
        return false;
    }

    /**
     * 创建需要进行保存的 用户对象
     *
     * @param registerDto 注册用户的参数实体对象
     * @return 需要进行注册的用户对象
     */
    private User generateUser(RegisterDto registerDto) {
        // 创建需要保存的用户对象
        User user = new User();
        // 进行值的 copy
        BeanUtil.copyProperties(registerDto, user);
        // 设置用户类型
        user.setType((byte) 1);
        // 设置用户密码
        user.setPassword(BCrypt.hashpw(registerDto.getPassword(), BCrypt.gensalt()));
        // 设置是否设置支付密码
        user.setPaypassSetting(false);
        // 设置谷歌的认证状态
        user.setGaStatus(false);
        // 设置用户的认证状态
        user.setAuthStatus((byte) 0);
        // 设置用户登录次数
        user.setLogins(0);
        // 设置当前用户的状态
        user.setStatus((byte) 1);
        // 设置该用户的邀请码，随机生成一个 6 位的邀请码
        user.setInviteCode(RandomUtil.randomString(12));
        // 查看传入的邀请码是否为空，不为空查询邀请码用户
        if (StringUtils.isNotBlank(registerDto.getInvitionCode())) {
            // 设置直接邀请 id，调用方法进行查询邀请用户人 ID
            User inviteUser = getOne(new LambdaQueryWrapper<User>().eq(User::getInviteCode, registerDto.getInvitionCode()));
            if (inviteUser != null)
                user.setDirectInviteid(String.valueOf(inviteUser.getId()));
        }
        // 返回用户对象
        return user;
    }
}
